
package com.mephi.controller.action;


import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.log4j.Logger;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import com.mephi.MephistoChess;
import com.mephi.interfaces.Game;
import com.mephi.interfaces.LoadSaveGame;
import com.mephi.interfaces.Profile;
import com.mephi.io.LoadSaveGameImpl;
import com.mephi.model.Move;
import com.mephi.util.AuxClass;
import com.mephi.util.Constants;
import com.mephi.util.Ext;
import com.mephi.util.PieceColor;
import com.mephi.util.PieceLoaderKey;
import com.mephi.util.filter.FileFilter;


/**
 * Simple implementation of saving game action in another thread.
 * @author mephisto
 * 2011-05-28
 * 1.0
 */
public class SaveGameAction implements Runnable
{
	public SaveGameAction(Profile profile)
	{
		this.profile = profile;
	}

	@Override
	public void run()
	{
		DocumentBuilder builder = null;
		try 
		{
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			builder = factory.newDocumentBuilder();	          
		} 
		catch (ParserConfigurationException e)
		{
			logger.error(e);
			JOptionPane.showMessageDialog(MephistoChess.gui.getFraMainFrame(),
					e.getMessage(), "Problem with game!", JOptionPane.ERROR_MESSAGE);
		}
		//loading game to transform
        //FAKE
        Game<Move> game = profile.getGameMap().get("1");
        //END FAKE
        try
        {
        	AuxClass.checkArgument(game, new NullPointerException("There is no game to save!"));
        }
        catch (NullPointerException e)
        {
        	logger.error(e);
        	JOptionPane.showMessageDialog(MephistoChess.gui.getFraMainFrame(),
					e.getMessage(), "Problem with game!", JOptionPane.ERROR_MESSAGE);
        	return;
        }    
        
        Document doc = builder.newDocument();      
        //create the root element and add it to the document
        Element root = doc.createElement("profile");
        root.setAttribute("name", "mephisto");
        doc.appendChild(root);
        //create a comment and put it in the root element
        Comment comment = doc.createComment("Profile with saved games");
        root.appendChild(comment);            
        //create child element, add an attribute, and add to root
        Element games = doc.createElement("games");
        root.appendChild(games);
        Element gameElem = getGameHeaderElement(doc, game);
        games.appendChild(gameElem);  
        //<position>
        gameElem.appendChild(getPositionElement(doc, game));
        //<movesList>
        gameElem.appendChild(getMovesListElement(doc, game));
        
		LoadSaveGame<Move> loader = new LoadSaveGameImpl();
        //String filename = "/home/mephisto/workspace/MephistoChess/firstGame.xml";
	    //String filename = "/home/mephisto/firstGame.xml";
	    //System.getProperty("user.dir")+
	    //String filename =  "firstGame.xml"
        
        JFileChooser chooser = new JFileChooser();
        chooser.setCurrentDirectory(new File("."));
        List<String> extensionList =  new ArrayList<String>();
        extensionList.add(Ext.xml.toString());
        chooser.setFileFilter(new FileFilter(extensionList));
        int r = chooser.showSaveDialog(MephistoChess.gui.getFraMainFrame());
        if (r != JFileChooser.APPROVE_OPTION) return;
        //final File file = chooser.getSelectedFile();
        logger.info("Selected file: " + chooser.getSelectedFile().getAbsolutePath());
        //String filename =  "firstGame.xml";
        loader.saveGame(doc, chooser.getSelectedFile().getAbsolutePath());
	}
	
	private Element getGameHeaderElement(Document doc, Game<Move> game)
	{
		Date currentDate = ((GregorianCalendar)game.getCalendar()).getTime();
        Date currentTime = currentDate;
        DateFormat currentDateFormat;
        DateFormat currentTimeFormat;
        
        Locale currentLocale = Locale.GERMAN;
        //int dateStyle = DateFormat.MEDIUM;
        currentDateFormat = new SimpleDateFormat("yyyy.MM.dd");
        //DateFormat.getDateInstance(dateStyle, currentLocale);
        String date = currentDateFormat.format(currentDate);

        int timeStyle = DateFormat.MEDIUM;
        currentTimeFormat = DateFormat.getTimeInstance(timeStyle, currentLocale);
        String time = currentTimeFormat.format(currentTime);

        Element gameElem = doc.createElement("game");
        gameElem.setAttribute("event", game.getEvent());
        gameElem.setAttribute("site", game.getSite());
        gameElem.setAttribute("date", date);
        gameElem.setAttribute("round", Integer.toString(game.getRound()));
        gameElem.setAttribute("white", game.getWhite());
        gameElem.setAttribute("black", game.getBlack());
        gameElem.setAttribute("result", game.getResult().toString());
        gameElem.setAttribute("time", time);
        gameElem.setAttribute("timeControl", game.getTimeControl());
        gameElem.setAttribute("whiteElo", Integer.toString(game.getWhiteElo()));
        gameElem.setAttribute("blackElo", Integer.toString(game.getBlackElo()));
        
		return gameElem;
	}
	
	private Element getMovesListElement(Document doc, Game<Move> game)
	{
		Element movesList = doc.createElement("movesList");     
        StringBuilder strB = new StringBuilder();
        List<Move> list = game.getMovesList();
        for(int i = 0, size = list.size(); i < size; ++i)
        {
        	Element moveElem = doc.createElement("move");
        	moveElem.setAttribute("number", Integer.toString(i+1));
        	Move move = list.get(i); 
        	strB.append(move.getWhiteMove()).append(Constants.SPACE_STRING).
        				append(move.getBlackMove());
            Text moveText = doc.createTextNode(strB.toString());
            moveElem.appendChild(moveText);
            strB.delete(0, strB.length());
            movesList.appendChild(moveElem);
        }
        return movesList;
	}
	
	private Element getPositionElement(Document doc, Game<Move> game)
	{
		Element positionElem = doc.createElement("position");  
        positionElem.appendChild(getPositionNode(doc, game, 
        		PieceColor.WHITE.toString().toLowerCase()));
        positionElem.appendChild(getPositionNode(doc, game, 
        		PieceColor.BLACK.toString().toLowerCase()));    
		return positionElem;
	}
	
	private Element getPositionNode(Document doc, Game<Move> game, String elemName)
	{
		Element elem = doc.createElement(elemName);
		Map<String, PieceLoaderKey> piecesMap = null;
		//the order is K,Q,R,B,N,p
		List<StringBuilder> piecesStr = new ArrayList<StringBuilder>(6);
		for (int i=0; i<7; ++i)
			piecesStr.add(new StringBuilder());
		
		if (elemName.equals(PieceColor.WHITE.toString().toLowerCase()))
			piecesMap = game.getPosition().getWhitePosition();
		else
			piecesMap = game.getPosition().getBlackPosition();

		
		Set<String> set = piecesMap.keySet();	
		for (String key : set)
		{
			PieceLoaderKey pcsKey = piecesMap.get(key);			
			switch (pcsKey)
			{
			case wK:
			case bK:
				piecesStr.get(0).append(key).append(Constants.COMMA_STRING);
				break;
			case wQ:
			case bQ:
				piecesStr.get(1).append(key).append(Constants.COMMA_STRING);
				break;
			case wR:
			case bR:
				piecesStr.get(2).append(key).append(Constants.COMMA_STRING);
				break;
			case wB:
			case bB:
				piecesStr.get(3).append(key).append(Constants.COMMA_STRING);	
				break;
			case wN:
			case bN:
				piecesStr.get(4).append(key).append(Constants.COMMA_STRING);	
				break;
			case wp:
			case bp:
				piecesStr.get(5).append(key).append(Constants.COMMA_STRING);
				break;
			}
			for(StringBuilder it : piecesStr)
				if (it.lastIndexOf(Constants.COMMA_STRING) == (it.length()-1) && it.length() > 0)
					it.deleteCharAt(it.length()-1);
		}
		
		elem.setAttribute(Constants.KING, piecesStr.get(0).toString());
		elem.setAttribute(Constants.QUEENS, piecesStr.get(1).toString());
		elem.setAttribute(Constants.ROOKS, piecesStr.get(2).toString());
		elem.setAttribute(Constants.BISHOPS, piecesStr.get(3).toString());
		elem.setAttribute(Constants.KNIGHTS, piecesStr.get(4).toString());
		elem.setAttribute(Constants.PAWNS, piecesStr.get(5).toString());
		return elem;
	}
	
	
	private Logger logger = Logger.getLogger("LOG");
	private Profile profile;
}
